package Oidc

import (
	"context"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/mitchellh/mapstructure"
	"github.com/sirupsen/logrus"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"kubehark/kubehark-framwork/pkg/Oidc"
	"kubehark/kubehark-framwork/pkg/Plugin/Plugins"
	"net/http"
	"strings"
)

type OidcPlugin struct {
	Config OidcConfig
}

type OidcConfig struct {
	ClientID string `json:"clientid"`
	Issuer   string `json:"issuer"`
	Secret   string `json:"secret"`
}

func (this *OidcPlugin) SetConfigFromInterface(data interface{}) Plugins.PluginInterface {
	theInforMap := data.(map[string]interface{})
	var Config OidcConfig
	if err := mapstructure.Decode(theInforMap, &Config); err != nil {
		logrus.Error(err.Error())
	}
	return &OidcPlugin{
		Config: Config,
	}

}

func (this *OidcPlugin) RunPlugin(c *gin.Context) (err error) {
	authorization := strings.Split(c.Request.Header.Get("Authorization"), " ")
	if len(authorization) != 2 {
		c.JSON(http.StatusUnauthorized, metav1.Status{
			Code:    http.StatusUnauthorized,
			Message: "Bearer token required",
		})
		c.Abort()
		return errors.New("Bearer token required")
	}
	authorizationType := authorization[0]
	if authorizationType != "Bearer" {
		c.JSON(http.StatusUnauthorized, metav1.Status{
			Code:    http.StatusUnauthorized,
			Message: "Bearer token required",
		})
		return errors.New("Bearer token required")
	}

	authorizationToken := authorization[1]
	oidcApp, err := oidc.Setup(
		this.Config.ClientID,
		this.Config.Issuer,
		this.Config.Secret,
	)

	if err != nil {
		c.JSON(http.StatusUnauthorized, metav1.Status{
			Code:    http.StatusUnauthorized,
			Message: err.Error(),
		})
		c.Abort()
		return
	}
	idToken, err := oidcApp.GetVerifier().Verify(context.Background(), authorizationToken)

	if err != nil {
		c.JSON(http.StatusUnauthorized, metav1.Status{
			Code:    http.StatusUnauthorized,
			Message: err.Error(),
		})

		c.Abort()
		return
	}

	var claims oidc.Claims
	if err := idToken.Claims(&claims); err != nil {
		c.JSON(http.StatusUnauthorized, metav1.Status{
			Code:    http.StatusUnauthorized,
			Message: fmt.Sprintf("error decoding ID token claims: %v", err),
		})
		c.Abort()
		return err
	}
	c.Set("user", claims.Name)
	c.Set("accessTokenHash", idToken.AccessTokenHash)
	//c.Next()
	return
}
